﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using PServiceBus.Core.Runtime.Gateway;
using System.Collections.Concurrent;
using PServiceBus.Core.Runtime;
using PServiceBus.Core.Manager;
using System.Diagnostics;
using PServiceBus.Gateway.Interfaces;
using PServiceBus.Gateway.Interfaces.Commands;
using PServiceBus.Gateway.Interfaces.DTO;

namespace PServiceBus.Services.Gateway.Services {
    public sealed class RouterService : MessageServiceBase<RouterMessage> {

        static ConcurrentDictionary<string, PerfCounter> _perfCounters = new ConcurrentDictionary<string, PerfCounter>();
        const string TOTAL_CONNECTED_CLIENTS = "TotalConnectedClients";
        
        public RouterService(string address) : base(address){}

        protected override void RegisterRequestResponse() {
            var router = ServiceLocator<IRouterService>.Get();
            if (router == null)
                throw new InvalidOperationException("ServiceLocator could not find an implementation of IRouterService.");
            router.Server = Server;
            router.RegisterRequestResponse();
        }

        protected override void RegisterCommands() {
            RegisterCommand(SetConnectedClients);
            RegisterCommand(DeleteService);
        }

        private static void SetConnectedClients(RouterMessage command) {
            var serviceInfo = ServiceInfo.Load(s => s.ID == command.ID);
            if (serviceInfo == null) return;
            var serviceName = serviceInfo.ServiceName;
            if (command.Decrement) serviceInfo.TotalConnectedClients--;
            else serviceInfo.TotalConnectedClients++;
            serviceInfo.Update();
            UpdateTotalConnectedClientsPerfCounter(serviceName, value: serviceInfo.TotalConnectedClients);        
        }

        private static void DeleteService(RouterMessage command) {
            var service = ServiceInfo.Load(s => s.ID == command.ID);
            if (service == null) return;
            service.Delete();
        }

        private static void CreatePerfCounterIfNotExist(string serviceName) {
            if (_perfCounters.ContainsKey(serviceName)) return;
            var perfCounter = new PerfCounter();
            perfCounter.Load(serviceName, new Dictionary<string, System.Diagnostics.PerformanceCounterType>() { 
               {TOTAL_CONNECTED_CLIENTS, PerformanceCounterType.NumberOfItems64}
            });
            _perfCounters[serviceName] = perfCounter;
        }

        private static void UpdateTotalConnectedClientsPerfCounter(string serviceName, long value) {
            CreatePerfCounterIfNotExist(serviceName);
            var perfCounter = _perfCounters.ContainsKey(serviceName) ? _perfCounters[serviceName] : null;
            if (perfCounter == null) return;
            perfCounter.SetValue(TOTAL_CONNECTED_CLIENTS, Math.Max(0, value));
        }
    }
}
